using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.Threading;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Xilium.CefGlue.Avalonia;

namespace Ava.Web;

public partial class BrowserView : UserControl
{
    private AvaloniaCefBrowser browser;

    public event Action<string> TitleChanged;

    public BrowserView()
    {
        InitializeComponent();

        var browserWrapper = this.FindControl<Decorator>("browserWrapper");

        browser = new AvaloniaCefBrowser();
        browser.Address = "https://www.bilibili.com/";
        browser.RegisterJavascriptObject(new BindingTestClass(), "boundBeforeLoadObject");
        browser.LoadStart += OnBrowserLoadStart;
        browser.TitleChanged += OnBrowserTitleChanged;
        browserWrapper.Child = browser;
    }


    private void OnAddressTextBoxKeyDown(object sender, global::Avalonia.Input.KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            browser.Address = ((TextBox)sender).Text;
        }
    }

    public async void EvaluateJavascript()
    {
        Console.WriteLine(await browser.EvaluateJavaScript<string>("\"Hello World!\""));

        Console.WriteLine(await browser.EvaluateJavaScript<int>("1+1"));

        Console.WriteLine(await browser.EvaluateJavaScript<bool>("false"));

        Console.WriteLine(await browser.EvaluateJavaScript<double>("1.5+1.5"));

        Console.WriteLine(await browser.EvaluateJavaScript<double>("3+1.5"));

        Console.WriteLine(await browser.EvaluateJavaScript<DateTime>("new Date()"));

        //Console.WriteLine(string.Join(", ", await browser.EvaluateJavaScript<object[]>("[1, 2, 3]")));

        //Console.WriteLine(string.Join(", ", (await browser.EvaluateJavaScript<ExpandoObject>("(function() { return { a: 'valueA', b: 1, c: true } })()")).Select(p => p.Key + ":" + p.Value)));
    }

    public void BindJavascriptObject()
    {
        const string TestObject = "dotNetObject";

        var obj = new BindingTestClass();
        browser.RegisterJavascriptObject(obj, "dotNetObject");

        var methods = obj.GetType().GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
                                   .Where(m => m.GetParameters().Length == 0)
                                   .Select(m => m.Name.Substring(0, 1).ToLowerInvariant() + m.Name.Substring(1));

        var script = "(function () {" +
            "let calls = [];" +
            //string.Join("", methods.Select(m => $"calls.push({{ name: '{m}', promise: {TestObject}.{m}() }});")) +
            $"calls.push({{ name: 'getObjectWithParams', promise: {TestObject}.getObjectWithParams(5, 'a string', {{ Name: 'obj name', Value: 10 }}, [ 1, 2 ]) }});" +
            "calls.forEach(c => c.promise.then(r => console.log(c.name + ': ' + JSON.stringify(r))).catch(e => console.log(e)));" +
            "})()";

        browser.ExecuteJavaScript(script);
    }

    private void OnBrowserLoadStart(object sender, Xilium.CefGlue.Common.Events.LoadStartEventArgs e)
    {
        if (e.Frame.Browser.IsPopup || !e.Frame.IsMain)
        {
            return;
        }

        Dispatcher.UIThread.Post(() =>
        {
            var addressTextBox = this.FindControl<TextBox>("addressTextBox");

            addressTextBox.Text = e.Frame.Url;
        });
    }

    private void OnBrowserTitleChanged(object sender, string title)
    {
        TitleChanged?.Invoke(title);
    }

    public void OpenDevTools()
    {
        browser.ShowDeveloperTools();

    }

    public void Dispose()
    {
        browser.Dispose();
    }


    private void Button_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
    {
        if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || desktop.MainWindow?.StorageProvider is not { } provider)
            throw new NullReferenceException("empty");
        var folder = provider.OpenFolderPickerAsync(new Avalonia.Platform.Storage.FolderPickerOpenOptions()
        {
            Title = "file",
            AllowMultiple = false
        });
        var path = folder.Result.FirstOrDefault()?.Path;
        var spath = path?.LocalPath;
        if (path == null)
            return;
        if (!Directory.Exists(spath))
            Directory.CreateDirectory(spath);
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            if (!spath.EndsWith("\\"))
                spath += "\\";

        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            if (!spath.EndsWith('/'))
                spath += "/";
        }
        addressTextBox.Text = spath + "1.docx";


    }


}